//
//  InputMouseManage.swift
//  iDev
//
//  Created by lbxia on 2021/9/8.
//

import Foundation
import Cocoa


/*
 左键按下，左键抬起，右键按下
 
 */
class InputMouseManage {
    
    static public let shared: InputMouseManage = InputMouseManage()
    
    var dragFirst = true
    var preMouseLoc: NSPoint = NSEvent.mouseLocation
    
    /*
     测试单个屏幕，多桌面，移动正常
     NSScreen 如果多个屏幕，应该如何计算，待macbook pro加外接显示测试
     */
     class func moveMouse(_ dx: CGFloat , _ dy: CGFloat) {
        
        //先监控移动前鼠标位置
        var mouseLoc = NSEvent.mouseLocation
        mouseLoc.y = NSHeight(NSScreen.screens[0].frame) - mouseLoc.y;
        
        //计算鼠标新位置
        let newLoc = CGPoint(x: mouseLoc.x-CGFloat(dx), y: mouseLoc.y+CGFloat(dy))
        print("moving \(dx) \(dy)")
        CGDisplayMoveCursorToPoint(0, newLoc)
    }
    

    
    
    /// 鼠标左键 按下或抬起，
    /// 问题：在编辑器里面编辑光标不会移动？(功能正常，由于当前在其他windows点击启动模拟功能，模拟点击第一次是次先切换到编辑器window,在模拟点击一次就编辑器位置就正常了)
    /// - Parameters:
    ///   - point: 鼠标按下位置，nil 表示取当前位置
    ///   - mouseDown: true->按下, false->抬起
    class func mouseLeftClick(_ point: CGPoint? = nil, mouseDown: Bool = true)  {
        
        
        var tmp = point
        
        if tmp == nil {
            
            //先监控移动前鼠标位置
            var mouseLoc = NSEvent.mouseLocation
            mouseLoc.y = NSHeight(NSScreen.screens[0].frame) - mouseLoc.y
            tmp = mouseLoc
        }
        
        let mouseLoc = tmp!
        
        guard let mouseEvent = CGEvent(mouseEventSource: nil,
                                       mouseType: mouseDown ? .leftMouseDown : .leftMouseUp,
                                mouseCursorPosition: mouseLoc,
                                mouseButton: .left
                                ) else {return}
        
        mouseEvent.post(tap: .cghidEventTap)
        
        if mouseDown == false {
            InputMouseManage.shared.dragFirst = true
        }
       
    }
    
    class func mouseLeftDoubleClick(_ point: CGPoint? = nil)  {
        
        var tmp = point
        
        if tmp == nil {
            
            //先监控移动前鼠标位置
            var mouseLoc = NSEvent.mouseLocation
            mouseLoc.y = NSHeight(NSScreen.screens[0].frame) - mouseLoc.y
            tmp = mouseLoc
        }
        
        let mouseLoc = tmp!
        
        guard let firstClickDownEvent = CGEvent(mouseEventSource: nil, mouseType: .leftMouseDown, mouseCursorPosition: mouseLoc, mouseButton: .left ) else {
            return
        }
        
        guard let firstClickUpEvent = CGEvent(mouseEventSource: nil, mouseType: .leftMouseUp, mouseCursorPosition: mouseLoc, mouseButton: .left ) else {
            return
        }
        
        guard let twoClickDownEvent = CGEvent(mouseEventSource: nil, mouseType: .leftMouseDown, mouseCursorPosition: mouseLoc, mouseButton: .left ) else {
            return
        }
        
        guard let twoClickUpEvent = CGEvent(mouseEventSource: nil, mouseType: .leftMouseUp, mouseCursorPosition: mouseLoc, mouseButton: .left ) else {
            return
        }
        
        firstClickDownEvent.setIntegerValueField(.mouseEventClickState, value: 1)
        firstClickDownEvent.post(tap: .cghidEventTap)
        
        firstClickUpEvent.setIntegerValueField(.mouseEventClickState, value: 1)
        firstClickUpEvent.post(tap: .cghidEventTap)
        
        twoClickDownEvent.setIntegerValueField(.mouseEventClickState, value: 2)
        twoClickDownEvent.post(tap: .cghidEventTap)
        
        twoClickUpEvent.setIntegerValueField(.mouseEventClickState, value: 2)
        twoClickUpEvent.post(tap: .cghidEventTap)
       
    }
   
    class func mouseRightClick(_ point: CGPoint? = nil, mouseDown: Bool = true)  {
        
        
        var tmp = point
        
        if tmp == nil {
            
            //先监控移动前鼠标位置
            var mouseLoc = NSEvent.mouseLocation
            mouseLoc.y = NSHeight(NSScreen.screens[0].frame) - mouseLoc.y
            tmp = mouseLoc
        }
        
        let mouseLoc = tmp!
        
        guard let mouseEvent = CGEvent(mouseEventSource: nil,
                                       mouseType: mouseDown ? .rightMouseDown : .rightMouseUp,
                                mouseCursorPosition: mouseLoc,
                                mouseButton: .right
                                ) else {return}
        
        mouseEvent.post(tap: .cghidEventTap)
       
    }
    
    /*
      swift drag

         鼠标左键拖动
         
         先左键按下，然后调用下面的代码，然后左键抬起，拖动结束，是客户端主动调用拖动，还是内部根据左键按键，然后鼠标移动，来调用拖动功能还是如何操作？
         
         
     */
        class func mouseLeftDrag(_ dx: CGFloat , _ dy: CGFloat)  {
            
            
            if InputMouseManage.shared.dragFirst  {
                
                //只会返回首次拖动的位置
                var mouseLoc = NSEvent.mouseLocation
                mouseLoc.y = NSHeight(NSScreen.screens[0].frame) - mouseLoc.y;
                
                InputMouseManage.shared.preMouseLoc = mouseLoc
                
                InputMouseManage.shared.dragFirst = false
            }
            
            let mouseLoc = InputMouseManage.shared.preMouseLoc
           
            //计算鼠标新位置
            let newLoc = CGPoint(x: mouseLoc.x+CGFloat(dx), y: mouseLoc.y+CGFloat(dy))
            
            InputMouseManage.shared.preMouseLoc = newLoc
            
            guard let mouseEvent = CGEvent(mouseEventSource: nil,
                                           mouseType: .leftMouseDragged,
                                    mouseCursorPosition: newLoc,
                                    mouseButton: .left
                                    ) else {return}
            
            mouseEvent.post(tap: .cghidEventTap)
           
        }
        
        //滚动 swift版本,客户端需要加算法，保持"惯性"才有 触摸板滑动的效果
        class func mouseScrollWheel(dx: Int32 = 0, dy: Int32 = 0, dz: Int32 = 0)  {
            
    //
            /*
             CGWheelCount wheelCount = 2; // 1 for Y-only, 2 for Y-X, 3 for Y-X-Z
             int32_t xScroll = −1; // Negative for right
             int32_t yScroll = −2; // Negative for down
             CGEventRef cgEvent = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitLine, wheelCount, yScroll, xScroll);

             // You can post the CGEvent to the event stream to have it automatically sent to the window under the cursor
             CGEventPost(kCGHIDEventTap, cgEvent);

             NSEvent *theEvent = [NSEvent eventWithCGEvent:cgEvent];
             CFRelease(cgEvent);

             // Or you can send the NSEvent directly to a view
             [theView scrollWheel:theEvent];
             */
            if #available(macOS 10.13, *) {
                
                let wheelCount = dz != 0 ? 3 : 2
                
                
                let wheelEvent = CGEvent(scrollWheelEvent2Source: nil, units: CGScrollEventUnit.line, wheelCount: UInt32(wheelCount), wheel1: dy, wheel2: dx, wheel3: dz)
                
                
                
                wheelEvent?.post(tap: .cghidEventTap)

                
            } else {
                // Fallback on earlier versions
            }
            
        }
    
    
    // MARK: ----- test code ----
    // MARK:  模拟鼠标输入
    //https://blog.csdn.net/weixin_41483813/article/details/82622742
    
    class func testMouseInput()  {
        
        // trackpad事件系统没有提供支持，只能使用模拟 键盘快捷键类似效果

        
        //测试，防止未弹出打开隐私->助理 提示
//        self.mouseLeftClick()
//        self.mouseLeftClick(mouseDown: false)
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            
            
            //尽量配对，否则可能会有小细节的问题，如拖动，总之需要左键抬起的状态的一些功能
//            self.mouseLeftClick(mouseDown: true)
//            self.mouseLeftClick(mouseDown: false)
            
            
            //右键
//            self.mouseRightClick(mouseDown: true)
//            self.mouseRightClick(mouseDown: false)

            
    //左键双击
//            self.mouseLeftDoubleClick()
            
            
            
            // drag swift 语言
//            Thread.detachNewThread {
//
//                //开始前 click down
//                self.mouseLeftClick(mouseDown: true)
//
//
//                struct  Tmp {
//                    static var mouseX = 0
//                }
//
//                for i in 1..<60{
//                    Tmp.mouseX += i;
//
//                    self.mouseLeftDrag(1, 1)
//
//                    Thread.sleep(forTimeInterval: 0.01)
//                }
//
//                //结束： click up
//                DispatchQueue.main.asyncAfter(deadline: .now()+1) {
//                    self.mouseLeftClick(mouseDown:false)
//
//                }
//            }
            
            
            
            //上下滑动，左右滑动 wheel swift版本
//            Thread.detachNewThread {
//
//                for i in 1..<160{
//
//                    //上下滑动
//                    self.mouseScrollWheel(dx: 0, dy: Int32(i), dz: 0)
//
//                    Thread.sleep(forTimeInterval: 0.1/Double(i))
//                }
//
//
//                for i in 1..<160{
//
//                    //左右滑动
//                    self.mouseScrollWheel(dx: Int32(i), dy: 0, dz: 0)
//
//                    Thread.sleep(forTimeInterval: 0.1/Double(i))
//                }
//
//            }
           
            //移动
            self.testMouseMove()
            
        }
        
    }
    
    class func  testMouseMove()  {
        
        struct Tmp {
           static var mouseX = 0;
        }
        
        Thread.detachNewThread {
            
            for i in 1..<1000{
                Tmp.mouseX += i*2;
                InputMouseManage.moveMouse(1, 0)
                Thread.sleep(forTimeInterval: 0.005)
            }
        }
    }
    
    // MARK: --- c语言版本---
    
    //调用C语言版本 drag
    class func mouseDrag(_ mouseLoc: NSPoint, _ dx:CGFloat , _ dy:CGFloat, _ dragFirst: Bool = true)  {
        
        struct dragRecord{
            static var newLoc: CGPoint?
        }
        
        if dragFirst {
            
            //只会返回首次拖动的位置
            var mouseLoc = NSEvent.mouseLocation
            mouseLoc.y = NSHeight(NSScreen.screens[0].frame) - mouseLoc.y;
            
            dragRecord.newLoc = mouseLoc
        }
        
        
        
        
//        var mouseLoc = NSEvent.mouseLocation
//        mouseLoc.y = NSHeight(NSScreen.screens[0].frame) - mouseLoc.y;
        
        let mouseLoc = dragRecord.newLoc!
       
        //计算鼠标新位置
        let newLoc = CGPoint(x: mouseLoc.x+CGFloat(dx), y: mouseLoc.y+CGFloat(dy))
        
        dragRecord.newLoc = newLoc
        
        
        
        mouse_left_drag_to(Float(newLoc.x),Float(newLoc.y))
       
        
       
        
        print("drag")

    }
}
